import { container, singleton } from "src/common/services/di";

/**
 * type such as click,movein,moveout,mousein,mouseout
 */
interface YMEventType {
  type: string;
  message: any;
  target?: any;
}

interface InterfaceYMEvent {
  readonly name: string;
  once(type: string, listener: (event: YMEventType) => void): void;
  addEventListener(type: string, listener: (event: YMEventType) => void): void;
  has(type: string, listener: (event: YMEventType) => void): boolean;
  remove(type: string, listener: (event: YMEventType) => void): void;
  dispatch(event: YMEventType): void;
}

export interface Event<T> {
  (listener: (e: T) => any, args?: any): void;
}

export class YMEvent implements InterfaceYMEvent {
  private readonly _listener: any = {};
  public name = "YMEvent";

  once(type: string, listener: (event: YMEventType) => void){
    const listeners = this._listener;

    if(listeners[type] === undefined){
      listeners[type] = [];
    }

    if(listeners[type].indexOf(listener) === -1){
      listeners[type].push(listener);
    }
  }

  addEventListener(type: string, listener: (event: YMEventType) => void): void {
    const listeners = this._listener;

    if(listeners[type] === undefined){
      listeners[type] = [];
    };

    if(listeners[type].indexOf(listener) === -1){
      listeners[type].push(listener);
    };
  };

  has(type: string, listener: (event: YMEventType) => void):boolean {
    if( this._listener === undefined ) return false;

    const listeners = this._listener;
    
    return listeners[type] !== undefined && listeners[type].indexOf(listener) !== -1
  };

  remove(type: string, listener: (event: YMEventType) => void): void {
    if( this._listener === undefined ) return;

    const listeners = this._listener;
    const listenerArray = listeners[type];

    if(listenerArray === undefined) return;

    const index = listenerArray.indexOf(listener);
    if(index !== -1){
      listenerArray.splice( index, 1 );
    }
  };

  dispatch(event: YMEventType): void {
    if(this._listener === undefined) return;

    const listeners = this._listener;
    const listenerArray = listeners[event.type];

    if( listenerArray === undefined ) return;

    event.target = this;
    const array = listenerArray.slice( 0 );
    for(let i = 0, l = array.length; i < l; i++ ){
      array[i].call( this, event );
    }
  };
};

/**
 * 使用tsyrings的依赖注入，
 * 应该是类似在浏览器window下维持一个全局唯一的变量，单例，
 * 然后在网站启动的时候也启动，供全局调用。
 * 这个是把具体的实现和服务分离开来，后期可更换实现，而不用去修改服务
 */
@singleton()
export class YMEventService implements InterfaceYMEvent {
  public name = '';
  private event: any;
  constructor(){
    const event = new YMEvent();
    this.name = event.name;
    this.event = event;
  };

  once(type: string, listener: (event: YMEventType) => void): void {
      this.event.once(type, listener);
  };
  addEventListener(type: string, listener: (event: YMEventType) => void): void {
      this.event.addEventListener(type, listener);
  };
  has(type: string, listener: (event: YMEventType) => void): boolean {
      return this.event.has(type, listener);
  };
  remove(type: string, listener: (event: YMEventType) => void): void {
      this.event.remove(type, listener);
  };
  dispatch(event: YMEventType): void {
      this.event.dispatch(event);
  };
};

export const ymEventServiceFactory = () => {
  return container.resolve(YMEventService);
};